package cc.verywell.pureblock.msg.nfs.linkmap;

import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.concurrent.ConcurrentSkipListSet;

import cc.verywell.pureblock.log.Pblog;

/**
* 
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年6月16日 下午3:36:05
*/
public class EasyTableMemLog implements Closeable {

	private final Path file;
	private final OutputStream write;
	private final ByteBuffer bb;
	private boolean closed = false;
	public EasyTableMemLog(Path file) {
		this.file = file;
		try {
			write = Files.newOutputStream(file, StandardOpenOption.CREATE,StandardOpenOption.APPEND);
		} catch (IOException e) {
			throw new EasyIOException(e);
		}
		bb = ByteBuffer.allocate(4);
		bb.order(ByteOrder.BIG_ENDIAN);
	}
	@Override
	public void close(){
		if(closed)return;
		closed = true;
		try {
			write.close();
		} catch (IOException e) {
			if(Pblog.FS)Pblog.FS(e);
		}
	}
	public void delete() {
		close();
		try {
			Files.delete(file);
		} catch (IOException e) {
			if(Pblog.FS)Pblog.FS(e);
		}
	}

	public void add(LinkCell add) {
		try {
			bb.clear();
			bb.putInt(add.encodeSize());
			write.write(bb.array());
			write.write(add.encoded);
			write.flush();
		} catch (IOException e) {
			throw new EasyIOException(e);
		}
	}
	public void addAll(Collection<? extends LinkCell>  adds) {
		try {
			for (LinkCell add : adds) {
				bb.clear();
				bb.putInt(add.encodeSize());
				write.write(bb.array());
				write.write(add.encoded);
			}
			write.flush();
		} catch (IOException e) {
			throw new EasyIOException(e);
		}
	}
	
	static public TableReadLog readLog(long fileNumber, Path file) {
		long seq = Long.MIN_VALUE;
		long pos = 0;
		ByteBuffer bb = ByteBuffer.allocate(4);
		ConcurrentSkipListSet<LinkCell> map  = new ConcurrentSkipListSet<LinkCell>();
		try(InputStream in = Files.newInputStream(file, StandardOpenOption.READ)){
			while(in.read(bb.array())==4) {
				int i = bb.getInt();
				bb.clear();
				byte[] b = new byte[i];
				if(i!=in.read(b)) {
					throw new EOFException();
				}
				LinkCell c = new LinkCell(b);
				pos = i+4;
				map.add(c);
				seq = Math.max(seq, c.getSeq());
			}
		} catch (IOException e) {
			if(Pblog.FS)Pblog.FS(e);
		}
		try {
			if(Files.size(file)!=pos) {
				if(Pblog.FS)Pblog.FS("Drop data ",Files.size(file)-pos," at ",file);
				try(AsynchronousFileChannel channel = AsynchronousFileChannel.open(file, StandardOpenOption.WRITE).truncate(pos)){}
			}
		} catch (IOException e) {
			throw new EasyIOException(e);
		}
		EasyTableMemLog log = new EasyTableMemLog(file);
		return new TableReadLog(new EasyTableMem(fileNumber, map, log),seq);
	}
	static public class TableReadLog{
		final public EasyTableMem table;
		final public long bigest_seq;
		public TableReadLog(EasyTableMem table, long bigest_seq) {
			this.table = table;
			this.bigest_seq = bigest_seq;
		}
		
	}


}
